package com.ray.tool.date;

import com.ray.tool.common.constant.RayDateConstants;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 日期工具类 - 完全仅依赖于JDK8
 *
 * @author LiaoYuXing-Ray
 * @version 1.0
 * @createDate 2023/11/26 9:19
 **/
@SuppressWarnings("unused")
public class RayDateTools {

    /**
     * 工具类中的方法都是静态方法访问的，因此将构造器私有不允许创建对象
     *
     * @author LiaoYuXing-Ray 2023/9/7 10:28
     */
    private RayDateTools() {
        throw new AssertionError();
    }


    //================ Instant start ====================

    /**
     * 获取当前时间格式化字符串 - 精确到毫秒
     * 格式：{@link RayDateConstants#DATE_PATTERN}
     *
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getNowTime() {
        return getStringInstant(Instant.now());
    }

    /**
     * 通过[Instant]类 获取格式化时间字符串 - 默认精确到毫秒
     * 格式：{@link RayDateConstants#DATE_TIME_FORMATTER}
     *
     * @param instant 要格式化的时间
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringInstant(Instant instant) {
        return getStringInstant(instant, TimeUnit.MILLISECONDS);
    }


    /**
     * 通过[Instant]类 获取格式化时间字符串 - 精确{@link TimeUnit}
     * 格式：{@link RayDateConstants#DATE_TIME_FORMATTER}
     *
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringInstant(TimeUnit timeUnit) {
        return getStringInstant(Instant.now(), timeUnit);
    }

    /**
     * 通过[Instant]类 获取格式化时间字符串 - 精确{@link TimeUnit}
     * 格式：{@link RayDateConstants#DATE_TIME_FORMATTER}
     *
     * @param instant  要格式化的时间
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringInstant(Instant instant, TimeUnit timeUnit) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        StringBuilder builder = new StringBuilder();
        RayDateConstants.DATE_TIME_FORMATTER.formatTo(localDateTime, builder);
        String nowTimeStr = builder.toString();
        return nowTimeStr.substring(0, getDatePattenPosition(timeUnit));
    }

    //================ Instant end


    //================ Date start ====================

    /**
     * 通过[Date]类 获取当前时间字符串 - 默认精确到毫秒
     * 格式：{@link RayDateConstants#SIMPLE_DATE_FORMAT}
     *
     * @param date 要格式化的时间
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringDate(Date date) {
        return getStringDate(date, TimeUnit.MILLISECONDS);
    }

    /**
     * 通过[Date]类 获取当前时间字符串 - 精确{@link TimeUnit}
     * 格式：{@link RayDateConstants#SIMPLE_DATE_FORMAT}
     *
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringDate(TimeUnit timeUnit) {
        return getStringDate(new Date(), timeUnit);
    }

    /**
     * 通过Date类 获取当前时间字符串 - 精确{@link TimeUnit}
     * 格式：{@link RayDateConstants#SIMPLE_DATE_FORMAT}
     *
     * @param date     要格式化的时间
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:31
     **/
    public static String getStringDate(Date date, TimeUnit timeUnit) {
        String nowTimeStr = RayDateConstants.SIMPLE_DATE_FORMAT.format(date);
        return nowTimeStr.substring(0, getDatePattenPosition(timeUnit));
    }

    /**
     * 根据传入的日期字符串和指定的格式，获取对应的Date对象
     *
     * @param dateString 传入的日期字符串
     * @param format     指定的日期格式
     * @return 对应的Date对象
     * @author LiaoYuXing-Ray 2023/10/17 15:58
     **/
    public static Date getDateStringToDate(String dateString, String format) {
        try {
            return (new SimpleDateFormat(format)).parse(dateString);
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
        return null;
    }

    /**
     * 根据传入的日期字符串和多个指定格式，获取对应的Date对象
     *
     * @param dateString 传入的日期字符串
     * @param format     指定的日期格式数组
     * @return 对应的Date对象，如果所有格式都无法解析，则抛出异常
     * @author LiaoYuXing-Ray 2023/10/17 15:58
     */
    public static Date getDateStringToDate(String dateString, String[] format) {
        Date date;
        for (String s : format) {
            date = getDateStringToDate(dateString, s);
            if (date != null) {
                return date;
            }
        }
        throw new RuntimeException(String.format("SimpleDateFormat: parse %s formatter %s error!", dateString, Arrays.toString(format)));
    }

    /**
     * 根据传入的Date对象，保留其年月日信息，并返回结果
     *
     * @param src 传入的Date对象
     * @return 保留年月日信息的Date对象
     */
    public static Date retainYMD(Date src) {
        String format = "yyyy-MM-dd";
        return getDateStringToDate(DateString(src, format), format);
    }

    /**
     * 根据传入的Date对象和指定的格式，获取对应的日期字符串
     *
     * @param date   传入的Date对象
     * @param format 指定的日期格式
     * @return 对应的日期字符串
     */
    public static String DateString(Date date, String format) {
        return date == null ? "" : (new SimpleDateFormat(format)).format(date);
    }

    /**
     * 根据传入的日期字符串，获取对应的Date对象
     *
     * @param src 传入的日期字符串
     * @return 对应的Date对象
     */
    public static Date StringDate(String src) {
        try {
            return RayDateConstants.SIMPLE_DATE_FORMAT_14.parse(src);
        } catch (Exception var2) {
            return null;
        }
    }
    //================ Date end


    /**
     * 获取格式化日期 - 格式化截取坐标 - 私有
     * 10到日、13到时、16到分、19到秒、23到毫秒
     *
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return int n 位格式化日期截取坐标，如："2023-09-07" 坐标为：10
     * @author LiaoYuXing-Ray 2023/9/14 17:27
     **/
    private static int getDatePattenPosition(TimeUnit timeUnit) {
        int n;
        switch (timeUnit) {
            case DAYS:
                n = 10;
                break;
            case HOURS:
                n = 13;
                break;
            case MINUTES:
                n = 16;
                break;
            case SECONDS:
                n = 19;
                break;
            case MILLISECONDS:
                n = 23;
                break;
            default:
                throw new RuntimeException("不支持的类型:" + timeUnit + "\t只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]");
        }
        return n;
    }

    /**
     * 获取纯数字日期 - 格式化截取坐标 - 私有
     * 8到日、10到时、12到分、14到秒、17到毫秒
     *
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return int n 位纯数字字符串截取坐标，如："2023-09-07" 坐标为：8
     * @author LiaoYuXing-Ray 2023/9/14 17:27
     **/
    private static int getDateStrPosition(TimeUnit timeUnit) {
        int n;
        switch (timeUnit) {
            case DAYS:
                n = 8;
                break;
            case HOURS:
                n = 10;
                break;
            case MINUTES:
                n = 12;
                break;
            case SECONDS:
                n = 14;
                break;
            case MILLISECONDS:
                n = 17;
                break;
            default:
                throw new RuntimeException("不支持的类型:" + timeUnit + "\t只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]");
        }
        return n;
    }

    /**
     * 获取当前日期的 n 位纯数字字符串，如："20230907"
     *
     * @param timeUnit 只支持[DAYS]、[HOURS]、[MINUTES]、[SECONDS]、[MILLISECONDS]
     * @return java.lang.String
     * @author LiaoYuXing-Ray 2023/9/14 16:45
     **/
    public static String getNumberStringNowTime(TimeUnit timeUnit) {
        String timeStr = RayDateConstants.DATE_STR.substring(0, getDateStrPosition(timeUnit));
        Instant now = Instant.now();
        LocalDateTime localDateTime = now.atZone(ZoneId.systemDefault()).toLocalDateTime();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(timeStr);
        return localDateTime.format(formatter);
    }


    /**
     * 获取今年的天数
     *
     * @return 今年的天数
     * @author LiaoYuXing-Ray 2023/10/20 14:50
     **/
    public static int getDaysInYear() {
        return LocalDate.now().lengthOfYear();
    }

    /**
     * 获取指定某年的天数
     *
     * @param year 指定的年份
     * @return 指定某年的天数
     * @author LiaoYuXing-Ray 2023/10/20 14:50
     **/
    public static int getDaysInYear(int year) {
        return LocalDate.of(year, 1, 1).lengthOfYear();
    }




}
